package com.yu.comcurrent;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.*;

/**
 * @PackageName: com.yu.comcurrent
 * @Description: 创建线程池的工具类
 * @Version: v1.0.0
 * @Author: yuweilin
 * @Date: 10:55
 * <p>
 * Modification History:
 * Date         Author          Version            Description
 * ------------------------------------------------------------
 * 2021/1/27      yuweilin         v1.0.0               新建
 */
@Slf4j
public class ThreadPoolFactory {
    private static final Map<String, ExecutorService> THREAD_POOLS = new ConcurrentHashMap<>();

    //阻止参数实例，所以后面全部都是static方法
    private ThreadPoolFactory(){}

    public static ExecutorService createCustomThreadPoolIfAbsent(String threadNamePrefix){
        CustomThreadPoolConfig config = new CustomThreadPoolConfig();
        return createCustomThreadPoolIfAbsent(config,threadNamePrefix,false);
    }

    public static ExecutorService createCustomThreadPoolIfAbsent(CustomThreadPoolConfig config,String namePrefix,boolean isDaemon){
        ExecutorService threadPool = THREAD_POOLS.computeIfAbsent(namePrefix, k -> createThreadPool(config, namePrefix, isDaemon));
        if (threadPool.isShutdown()||threadPool.isTerminated()){
            THREAD_POOLS.remove(namePrefix);
            threadPool = createThreadPool(config,namePrefix,isDaemon);
            THREAD_POOLS.put(namePrefix,threadPool);
        }
        return threadPool;
    }
    /**
     * 创建线程池
     */
    private static ExecutorService createThreadPool(CustomThreadPoolConfig config,String threadNamePrefix,Boolean daemon){
        ThreadFactory factory = createThreadFactory(threadNamePrefix, daemon);
        ThreadPoolExecutor.CallerRunsPolicy policy = new ThreadPoolExecutor.CallerRunsPolicy();
        return new ThreadPoolExecutor(config.getCoreSize(),config.getMaxsize(),config.getAliveTime(),
                config.getTimeUnit(),config.getWorkQueue(),factory, policy);
    }

    /**
     * 根据线程前缀和是否守护线程的参数来决定线程工厂
     * @param threadNamePrefix
     * @param daemon
     * @return
     */
    public static ThreadFactory createThreadFactory(String threadNamePrefix,Boolean daemon){
        if (null!=threadNamePrefix){
            if (daemon!=null){
                return new ThreadFactoryBuilder()
                        .setNameFormat(threadNamePrefix+"-%d")
                        .setDaemon(daemon).build();
            }else{
                return new ThreadFactoryBuilder().setNameFormat(threadNamePrefix+"-%d").build();
            }
        }
        return Executors.defaultThreadFactory();
    }

    public static void printThreadPoolStatus(ThreadPoolExecutor threadPool){
        ScheduledThreadPoolExecutor poolExecutor = new ScheduledThreadPoolExecutor(1, createThreadFactory("print-thread-pool-status", false));
        poolExecutor.scheduleAtFixedRate(()->{
            log.info("===========threadPool status==============");
            log.info("threadpool size:[{}]",threadPool.getPoolSize());
            log.info("active threads:[{}]",threadPool.getActiveCount());
        },0,1,TimeUnit.SECONDS);
    }

}
